
classdef ActiveRecord < handle
    properties
        id;
    end
    
    methods
        function list = all(obj)
            rs = obj.select(['select * from ' lower(class(obj))]);
            
            list = {};
            while(rs.next)
                inst = extractObj(obj, rs);
                list = [list inst];
            end
        end
        
        function list = findBy(obj, field, value)
            if(~ischar(value))
                value = num2str(value);
            else
                value = ['''' value ''''];
            end
            
            rs = obj.select(['select * from ' lower(class(obj)) ' where ' field '==' value ';']);
            
            list = {};
            while(rs.next)
                inst = extractObj(obj, rs);
                list = [list inst];
            end
        end
        
        function save(obj)
            rsCount = com.SqliteHelper.selectStatement(['select max(c.id) from ' lower(class(obj)) ' as c '], ActiveRecord.dbPath);
            count = rsCount.getInt(1);
            rsCount.close();
            
            p = properties(obj);
            
            sql = ['insert into ' lower(class(obj)) ''];
            sql_p0 = '';
            sql_p1 = '';
            for i=1:numel(p)
                if(strcmp(p{i}, 'id'))
                    value = num2str(count+1);
                else
                    eval(['v=obj.' p{i} ';']);
                    if(ischar(v))
                        value = v;
                        value = ['''' value ''''];
                    else
                        value = num2str(v);
                    end
                end
                
                if(i==1)
                    sql_p0 = p{i};
                    sql_p1 = value;
                else
                    sql_p0 = [sql_p0 ', ' p{i}];
                    sql_p1 = [sql_p1 ', ' value];
                end
            end
            
            sql = [sql '(' sql_p0 ') values (' sql_p1 ');']
            obj.update(sql);
        end
    end
    
    methods (Static)    
        function createTable(command)
            %% Example
            % ActiveRecord.createTable('address street text number int')
            command = regexp(command, ' ', 'split');
            sql = ['create table ' command{1} '(id int primary key not null'];
            
            for i=2:2:numel(command)
                sql = [sql ', ' command{i} ' ' command{i+1}];
            end
            
            sql = [sql ');'];
            com.SqliteHelper.updateStatement(sql, ActiveRecord.dbPath);
        end
    end
    
    methods (Hidden)
        function update(obj, sql)
            com.SqliteHelper.updateStatement(sql, obj.dbPath)
        end
        
        function out = select(obj, sql)
            out = com.SqliteHelper.selectStatement(sql, obj.dbPath);
        end
        
        function inst = extractObj(obj, rs)
            eval(['inst = ' class(obj) ';']);
                
            for i=1:rs.getColumnCount
                name = rs.getColumnName(i);
                type = rs.getColumnType(i);

                if(type == 4)
                    % Int
                    v = rs.getInt(i);
                elseif(type == 12)
                    % Text
                    v = char(rs.getString(i));
                else
                    error('Not implemented');
                end

                eval(['inst.' char(name) '= v;'])
            end
        end
    end
    
    methods (Static, Hidden)
        function out = dbPath(path)
            persistent p___;
            if(nargin), p___=path; end
            out = p___;
        end
    end
end

